﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Xml;
using System.Threading;
using System.Text.RegularExpressions;
using System.Data.SqlClient;
using BizUnit;

namespace Acme.BizTalk.BizUnit.Tests.TestSteps
{
    /// <summary>
    /// Replaces the EventLogCheckStep
    /// </summary>
    public class OrchestrationCompletedQuery : ITestStep
    {
        private const string LocalHATConnectionString = "server=.; database=biztalkdtadb; integrated security=sspi;";
        private const string HatQuery = "SELECT [ServiceInstance/InstanceID] As ServiceID FROM dbo.dtav_ServiceFacts WHERE ([Service/Type] = N'Orchestration') AND ([ServiceInstance/State] = N'Completed') AND ([Service/Name] = @OrchestrationName) AND ([ServiceInstance/StartTime] >= @TestStartDate) --AND ([ServiceInstance/EndTime] >= @TestStartDate)";

        #region ITestStep Members
        /// <summary>
        /// Replaces the EventLogCheckStep
        /// </summary>
        /// <param name="testConfig"></param>
        /// <param name="context"></param>
        public void Execute(System.Xml.XmlNode testConfig, Context context)
        {
            const int DefaultSleep = 20;

            int count = 0;
            int durationToCheck = context.ReadConfigAsInt32(testConfig, "DurationToCheckSeconds", false);
            int expectedResult = context.ReadConfigAsInt32(testConfig, "ExpectedNoOrchestrations", false);
            string orchestrationName = context.ReadConfigAsString(testConfig, "OrchestrationName", false);            
            bool failIfLess = context.ReadConfigAsBool(testConfig, "FailIfLess", true);
            bool failIfMore = context.ReadConfigAsBool(testConfig, "FailIfMore", true);

            string hatConnectionString = context.ReadConfigAsString(testConfig, "HATConnectionString", true);
            if (string.IsNullOrEmpty(hatConnectionString))
                hatConnectionString = LocalHATConnectionString;

            DateTime startDateTime = context.TestCaseStart;

            int noOrchestrations = 0;            
            while (count <= durationToCheck)
            {
                noOrchestrations = CountOrchestrations(hatConnectionString, orchestrationName, context.TestCaseStart);
                if (expectedResult == noOrchestrations)
                {
                    if (!failIfMore)                    
                        break; //Dont care if there are more instances we have found what we want                    
                }
                else if (noOrchestrations > expectedResult)
                {
                    if (failIfMore)
                        break;
                }
                else
                {
                    //Keep looping
                }

                count = count + durationToCheck;
                Thread.Sleep(new TimeSpan(0, 0, DefaultSleep));
            }

            if (expectedResult == noOrchestrations)            
                return; //This is fine                    
            else if (noOrchestrations > expectedResult)
            {
                if (failIfMore)
                    throw new ApplicationException("There are more orchestration instances than expected");                
            }
            else
            {
                if (failIfLess)
                    throw new ApplicationException("There are less orchestrations than expected");                
            }
            return; //This is fine
        }
        #endregion

        /// <summary>
        /// Counts the number of completed orchestrations
        /// </summary>
        /// <param name="connectionString"></param>
        /// <param name="orchestrationName"></param>
        /// <param name="testStart"></param>
        /// <returns></returns>
        private int CountOrchestrations(string connectionString, string orchestrationName, DateTime testStart)
        {
            int noRecords = 0;
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                using (SqlCommand cmd = new SqlCommand())
                {
                    cmd.Connection = conn;
                    cmd.CommandType = System.Data.CommandType.Text;
                    cmd.CommandText = HatQuery;
                    cmd.Parameters.AddWithValue("@OrchestrationName", orchestrationName);
                    cmd.Parameters.AddWithValue("@TestStartDate", testStart.ToUniversalTime());
                    conn.Open();
                    using (SqlDataReader rdr = cmd.ExecuteReader())
                    {
                        while (rdr.Read())
                        {
                            noRecords++;
                        }
                    }
                    conn.Close();
                }
            }
            return noRecords;
        }
    }
}

